package fr.generali.sas.facade.v1_0;

import java.text.MessageFormat;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.xml.bind.JAXBElement;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import fr.generali.sas.exception.BusinessException;
import fr.generali.sas.model.v1_0.InfoClientResponse;
import fr.generali.sas.model.v1_0.ObjectFactory;
import fr.generali.sas.service.flux.InternalFluxSynchroService;
import fr.generali.sas.service.v1_0.FluxClientServiceCallable;
import fr.generali.sas.service.v1_0.FluxServiceCallable;

@Component("sasFluxSyncFacade")
public class SASFluxSyncFacadeImpl implements SASFluxSyncFacade, InitializingBean {

	private static Logger log = LoggerFactory.getLogger(SASFluxSyncFacadeImpl.class);

	@Autowired
	ThreadPoolTaskExecutor taskExecutor;

	@Autowired
	InternalFluxSynchroService fluxSynchroService;

	ObjectFactory sasModelObjectFactory = new ObjectFactory();

	//TODO choix entre ThreadPoolTaskExecutor et org.springframework.core.task.SimpleAsyncTaskExecutor
	//TODO externaliser les parametres du TaskExecutor
	//TODO externaliser le timeout un long en ms
	
	@Override
	public void afterPropertiesSet() throws Exception {
		

	}

	@Override
	public JAXBElement<InfoClientResponse> makeRecupererClientResponse(String codeIntermediaire, String idClient) throws IllegalArgumentException, Exception {
		FluxServiceCallable serviceCallable = new FluxClientServiceCallable(fluxSynchroService);
		serviceCallable.setCodeIntermediaire(codeIntermediaire);
		serviceCallable.setIdClient(idClient);

		JAXBElement<InfoClientResponse> element = null;

		log.info("===DEB===Envoi tache pour [codeIntermediaire: {0}  idClient: {1}]",new Object[]{codeIntermediaire,idClient});
		Future<Object> future = taskExecutor.submit(serviceCallable);
		try {
			InfoClientResponse response = (InfoClientResponse) future.get(1000, TimeUnit.MILLISECONDS);
			log.info("===FIN===Retour tache pour [codeIntermediaire: {0}  idClient: {1}]",new Object[]{codeIntermediaire,idClient});
			element = this.sasModelObjectFactory.createRecupererClientResponse(response);
		} catch (TimeoutException te) {
			// ExecutionException ou InterruptedException => RAF car le thread
			// est arrété mais dans ce cas il faut effectuer un rollback car
			// interceptorTransactionnel Spring ne fera rien
			// ces Exception ne sont pas des runtime.
			// autre cas, timeout exception mais le traitement est ok.
			// TEST a effectuer
			
			String message =  MessageFormat.format("[codeIntermediaire: {0}  idClient: {1}]   TimeoutException(makeRecupererClientResponse) : la réservation et l'envoi du premier flux s'est effectue en plus de 1s ", new Object[]{codeIntermediaire,idClient});
			//log.warn("[codeIntermediaire: {}  idClient: {}]   TimeoutException : la réservation et l'envoi du premier flux s'est effectue en plus de  ", new Object[]{codeIntermediaire,idClient});
			// TODO on tue le thread et on remonte une exception
			future.cancel(true);
			//TODO lancement asynchrone d'une compensation ou faire future.get dans ce cas (compensation)
			
			//TODO enrichissement de l'erreur
			BusinessException be = new BusinessException(message, te);
			throw be;

		}

		return element;
	}

}
